<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue'
import gsap from 'gsap'
import { Observer } from 'gsap/Observer'

gsap.registerPlugin(Observer)

interface CarouselItem {
  id: number | string
  imageUrl: string
  text?: string
  [key: string]: any
}

const props = withDefaults(defineProps<{
  items: CarouselItem[]
  autoRotate?: boolean
  rotateSpeed?: number
  direction?: 'clockwise' | 'counter-clockwise'
  perspective?: number
  tiltAngle?: number
  itemWidth?: number
  itemHeight?: number
  pauseOnHover?: boolean
  ellipseRadiusX?: number  // 椭圆x轴半径(长半径)
  ellipseRadiusY?: number  // 椭圆y轴半径(短半径)
  depthOffset?: number     // z轴深度偏移
}>(), {
  autoRotate: true,
  rotateSpeed: 10,
  direction: 'clockwise',
  perspective: 600,
  tiltAngle: 34,
  itemWidth: 100,
  itemHeight: 100,
  pauseOnHover: true,
  ellipseRadiusX: 100,
  ellipseRadiusY: 300,
  depthOffset: -100
})

const emit = defineEmits(['item-click'])

const progress = ref(0)
const carouselRef = ref<HTMLElement | null>(null)
let autoAnimation: gsap.core.Tween | null = null
let resumeTimeout: any
let isUserInteracting = ref(false)
let manualAnimation: gsap.core.Tween | null = null
let observer: Observer | null = null
let animateFunc: (() => void) | null = null

const startAutoRotation = (fromValue?: number) => {
  if (!props.autoRotate) return

  if (autoAnimation) autoAnimation.kill()

  const startValue = fromValue !== undefined ? fromValue : progress.value
  const directionFactor = props.direction === 'clockwise' ? 1 : -1
  const endValue = startValue + directionFactor

  autoAnimation = gsap.to(progress, {
    value: endValue,
    duration: props.rotateSpeed,
    ease: 'none',
    modifiers: {
      value: (v) => v % 1
    },
    onComplete: () => {
      startAutoRotation(progress.value)
    }
  })
}

const scheduleAutoResume = () => {
  if (resumeTimeout) clearTimeout(resumeTimeout)
  isUserInteracting.value = true

  resumeTimeout = setTimeout(() => {
    isUserInteracting.value = false
    if (!manualAnimation?.isActive()) {
      startAutoRotation(progress.value)
    }
  }, 1500)
}

const handleItemClick = (item: CarouselItem) => {
  emit('item-click', item)
}

const calculateEllipsePosition = (angle: number) => {
  // 将进度转换为弧度(0-2π)
  const theta = angle * Math.PI * 2
  // 计算椭圆上的点坐标
  const x = -Math.sin(theta) * props.ellipseRadiusX
  const y = Math.cos(theta) * props.ellipseRadiusY
  // z坐标使用x轴半径计算，使近大远小效果更明显
  const z = Math.cos(theta) * props.ellipseRadiusX + props.depthOffset

  return { x, y, z }
}

const initCarousel = () => {
  if (!carouselRef.value) return

  // 清理之前的资源
  if (observer) observer.kill()
  if (autoAnimation) autoAnimation.kill()
  if (manualAnimation) manualAnimation.kill()
  if (animateFunc) gsap.ticker.remove(animateFunc)
  if (resumeTimeout) clearTimeout(resumeTimeout)

  animateFunc = () => {
    const items = carouselRef.value?.querySelectorAll('.carousel-item') || []
    items.forEach((item, index) => {
      // 计算每个项目在椭圆上的位置
      const angle = (index / items.length - progress.value)
      const { x, y, z } = calculateEllipsePosition(angle)

      // 根据z坐标计算缩放比例(透视效果)
      const scale = 0.5 + 0.5 * (z + props.ellipseRadiusX + Math.abs(props.depthOffset)) /
        (2 * props.ellipseRadiusX + Math.abs(props.depthOffset))

      // 根据位置设置项目样式
      gsap.set(item, {
        x: x,
        y: y,
        z: z,
        scale: scale,
        rotationY: 0,
        rotationX: 0,
        width: props.itemWidth,
        height: props.itemHeight,
        transformStyle: 'preserve-3d',
        transformOrigin: 'center center'
      })
    })
  }

  observer = Observer.create({
    target: carouselRef.value,
    type: "wheel,pointer",
    onPress: () => {
      if (!carouselRef.value) return
      carouselRef.value.style.cursor = 'grabbing'
      if (autoAnimation) autoAnimation.pause()
      isUserInteracting.value = true
    },
    onRelease: () => {
      if (!carouselRef.value) return
      carouselRef.value.style.cursor = 'grab'
      scheduleAutoResume()
    },
    onChange: (self) => {
      if (manualAnimation?.isActive()) manualAnimation.kill()

      const directionFactor = props.direction === 'clockwise' ? -1 : 1
      const p = self.event.type === 'wheel' ?
        self.deltaY * -0.0003 * directionFactor :
        self.deltaX * 0.003 * directionFactor

      manualAnimation = gsap.to(progress, {
        value: `+=${p}`,
        duration: 0.5,
        ease: 'power2.out',
        onUpdate: () => {
          isUserInteracting.value = true
          if (animateFunc) animateFunc()
        },
        onComplete: scheduleAutoResume
      })

      scheduleAutoResume()
    }
  })

  gsap.ticker.add(animateFunc)
  startAutoRotation()
}

// 监听props变化
watch(() => [
  props.autoRotate,
  props.direction,
  props.rotateSpeed,
  props.itemWidth,
  props.itemHeight,
  props.ellipseRadiusX,
  props.ellipseRadiusY,
  props.depthOffset
], () => {
  initCarousel()
}, { deep: true })

onMounted(() => {
  initCarousel()
})

onUnmounted(() => {
  if (observer) observer.kill()
  if (autoAnimation) autoAnimation.kill()
  if (manualAnimation) manualAnimation.kill()
  if (animateFunc) gsap.ticker.remove(animateFunc)
  if (resumeTimeout) clearTimeout(resumeTimeout)
})
</script>

<template>
  <div class="carousel-container">
    <div class="carousel-wrapper">
      <div ref="carouselRef" class="carousel" :style="{
        perspective: `${perspective}px`,
        transform: `rotateX(-${tiltAngle}deg)`
      }">
        <div v-for="(item, index) in items" :key="item.id" class="carousel-item"
          @mouseenter="pauseOnHover && autoAnimation?.pause()"
          @mouseleave="pauseOnHover && !isUserInteracting && autoAnimation?.resume()" @click="handleItemClick(item)">
          <slot name="item" :item="item" :index="index">
            <div class="default-item">
              <img v-if="item.imageUrl" :src="item.imageUrl" class="item-image" alt="">
              <div v-if="item.text" class="item-text">{{ item.text }}</div>
            </div>
          </slot>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
.carousel-container {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.carousel-wrapper {
  width: 100%;
  height: 100%;
  position: relative;
}

.carousel {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  transform-style: preserve-3d;
  user-select: none;
  cursor: grab;
  position: relative;
}

.carousel-item {
  position: absolute;
  display: flex;
  justify-content: center;
  align-items: center;
  backface-visibility: visible;
  will-change: transform;
  transform-style: preserve-3d;
  transition: transform 0.1s linear;
  cursor: pointer;
}

.default-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}

.item-image {
  max-width: 80%;
  max-height: 80%;
  object-fit: contain;
  transform: translateZ(20px);
}

.item-text {
  margin-top: 8px;
  transform: translateZ(20px);
  text-align: center;
  font-size: 14px;
}
</style>